#pragma once
#include"functional"


namespace cyq
{
	template<class T>
	class auto_ptr
	{
	public:
		//把资源交给对象来管理，在对象的生命周期内，资源有效，对象生命周期到了，资源释放
		//像指针一样使用
		auto_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{
			cout << "auto_ptr(T* ptr)" << endl;
		}

		auto_ptr(auto_ptr<T>& ap)
			:_ptr(ap._ptr)
		{
			cout << "auto_ptr(auto_ptr<T>& ap)" << endl;
			ap._ptr = nullptr;
		}

		~auto_ptr()
		{
			cout << "~auto_ptr()" << endl;
			delete _ptr;
		}

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};

	template<class T>
	class unique_ptr
	{
	public:
		//把资源交给对象来管理，在对象的生命周期内，资源有效，对象生命周期到了，资源释放
		//像指针一样使用
		unique_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{
			cout << "unique_ptr(T* ptr)" << endl;
		}

		unique_ptr(unique_ptr<T>& up) = delete;
		unique_ptr<T> operator=(unique_ptr<T>& up) = delete;

		~unique_ptr()
		{
			cout << "~unique_ptr()" << endl;
			delete _ptr;
		}

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};

	template<class T>
	class shared_ptr
	{
	public:
		//把资源交给对象来管理，在对象的生命周期内，资源有效，对象生命周期到了，资源释放
		//像指针一样使用
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			, _pcount(new int(1))
		{
			cout << "shared_ptr(T* ptr)" << endl;
		}

		//定制删除器
		template<class D>
		shared_ptr(T* ptr, D del)
			:_ptr(ptr)
			, _pcount(new int(1))
			,_del(del)
		{
			cout << "shared_ptr(T* ptr)" << endl;
		}


		shared_ptr(shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pcount(sp._pcount)
		{
			(*_pcount)++;
		}

		shared_ptr<T> operator=(const shared_ptr<T>& sp)
		{
			//自己给自己赋值
			if (_ptr==sp._ptr)
			{
				return *this;
			}

			if ((--(*_pcount)) == 0)
			{
				_del(_ptr);
				delete _pcount;
			}

			_pcount = sp._pcount;
			_ptr = sp._ptr;
			(*_pcount)++;

			
			return *this;
		}

		~shared_ptr()
		{
			if ((--(*_pcount)) == 0)
			{
				cout << "~shared_ptr()" << endl;
				_del(_ptr);
				delete _pcount;
			}
		}

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}

		int use_count() const
		{
			return *_pcount;
		}

		T* get() const
		{
			return _ptr;
		}
	private:
		T* _ptr;
		int* _pcount;
		function<void(T*)> _del = [](T* ptr) {delete ptr; };
	};

	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr()
			:_ptr(nullptr)
		{
		}

		weak_ptr(weak_ptr<T>& sp)
			:_ptr(sp._ptr)
		{
		}

		weak_ptr(shared_ptr<T>& sp)
			:_ptr(sp.get())
		{
		}

		weak_ptr<T> operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}

		weak_ptr<T> operator=(const weak_ptr<T>& sp)
		{
			_ptr = sp._ptr;
			return *this;
		}


		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}

	private:
		T* _ptr;
	};


}
